package org.theqcp.wow.api.wowhead.parsers;

import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;
import org.jdom.xpath.XPath;
import org.theqcp.wow.model.api.ProgressListener;
import org.theqcp.wow.model.items.Equipment;
import org.theqcp.wow.model.mechanics.Attribute;

/**
 * Parse the wowhead xml from the wowhead service.
 * 
 * @author angryundead
 *
 */
public class EquipmentParser {

	public List<Equipment> parse(String xml) {
		return this.parse(xml,null);
	}
	
	public List<Equipment> parse(String xml, ProgressListener listener) {
		
		//list
		List<Equipment> eqList = new ArrayList<Equipment>();
		
		if(listener != null) {
			listener.updateProgress(0);
		}
		
		//return empty equalizer list if the xml string is bad
		if(xml == null || xml.isEmpty()) return eqList;
		
		//get sax parser
		SAXBuilder builder = new SAXBuilder();
		
		//begin building
		try {
			//create xml document to parse
			Document xmldocument = builder.build(new StringReader(xml));
			
			//get element(s) with xpath
			XPath xpath = XPath.newInstance("/wowhead/item");
			
			//list
			@SuppressWarnings("unchecked")
			List<Object> elementList = xpath.selectNodes(xmldocument);

			if(listener != null) {
				listener.updateProgress(10);
			}
			
			//90% in loop
			double remains = 90 / elementList.size();
			double percent = 10;
			
			//loop through list of elements (equipment)
			for(Object item : elementList) {
				
				//get element of item
				Element itemElement = (Element)item;
				
				//get item id from element list
				String itemid = itemElement.getAttributeValue("id"); 
				
				//get item name from element list
				String itemName = itemElement.getChildTextTrim("name");
				
				//item class element
				Element classElement = itemElement.getChild("class");
				String classNumber = classElement.getAttributeValue("id");
				String className = classElement.getTextTrim();
				
				//item subclass element
				Element subClassElement = itemElement.getChild("subclass");
				String subClassNumber = subClassElement.getAttributeValue("id");
				String subClassName = subClassElement.getTextTrim();
				
				//get json string from elementList
				String jsonEquip = itemElement.getChildTextTrim("jsonEquip");
				
				//create new equipment now that data is present
				Equipment eq = new Equipment();
				
				//set value elements
				eq.setItemId(itemid);
				eq.setItemName(itemName);

								
				eq.setItemClassName(className);
				eq.setItemClassNumber(classNumber);
				eq.setItemSubClassName(subClassName);
				eq.setItemSubClassNumber(subClassNumber);				
				
				//get value hasmap
				HashMap<String, Double> jsonMap = this.parseJSON(jsonEquip);
				
				//get useful weapon stats
				eq.setStat(Attribute.AGILITY, this.getJSONStat("agi", jsonMap));
				eq.setStat(Attribute.ARMORPENETRATION, this.getJSONStat("armorpenrtng", jsonMap));
				eq.setStat(Attribute.ATTACKPOWER, this.getJSONStat("atkpwr", jsonMap));
				eq.setStat(Attribute.CRITRATING, this.getJSONStat("critstrkrtng", jsonMap));
				eq.setStat(Attribute.DAMAGELOW, this.getJSONStat("dmgmin1", jsonMap));
				eq.setStat(Attribute.DAMAGEHIGH, this.getJSONStat("dmgmax1", jsonMap));
				eq.setStat(Attribute.DPS, this.getJSONStat("dps", jsonMap));
				eq.setStat(Attribute.EXPERTISERATING, this.getJSONStat("exprtng", jsonMap));
				eq.setStat(Attribute.HITRATING, this.getJSONStat("hitrtng", jsonMap));
				eq.setStat(Attribute.INTELLECT, this.getJSONStat("int", jsonMap));
				eq.setStat(Attribute.MANAREGEN, this.getJSONStat("manargn", jsonMap));
				eq.setStat(Attribute.SPEED, this.getJSONStat("speed", jsonMap));
				eq.setStat(Attribute.SPELLPOWER, this.getJSONStat("splpwr", jsonMap));
				eq.setStat(Attribute.SPIRIT, this.getJSONStat("spi", jsonMap));
				eq.setStat(Attribute.STAMINIA, this.getJSONStat("sta", jsonMap));
				eq.setStat(Attribute.STRENGTH, this.getJSONStat("str", jsonMap));
				eq.setStat(Attribute.HASTERATING, this.getJSONStat("hastertng", jsonMap));
			
				//add item to list
				if(eq.getItemId() != null && !eq.getItemId().isEmpty()) {
					eqList.add(eq);
				}

				//update percentage
				percent += remains;
				if(listener != null) {
					listener.updateProgress(remains);
				}
			}
			
			//done!
			if(listener != null) {
				listener.updateProgress(100);
			}
			
		} catch (JDOMException e) {
			//can't recover
		} catch (IOException e) {
			//can't recover
		}		
		
		return eqList;
	}
	
	private HashMap<String, Double> parseJSON(String input) {
		
		//create json map
		HashMap<String, Double> jsonMap = new HashMap<String, Double>();
		
		//split on ","
		String[] jsonElements = input.split(",");
		
		//for each json object row
		for(String row : jsonElements) {
						
			//name value pair
			String name = row.split(":")[0];
			String value = row.split(":")[1];

			Double dValue = new Double(0.0);

			try {
				dValue = Double.parseDouble(value);
			} catch (NumberFormatException nfex) {
				//could not format number
			}
			
			jsonMap.put(name, dValue);
		}
		
		
		return jsonMap;
	}
	
	private Double getJSONStat(String statId, HashMap<String, Double> jsonTable) {
		
		Double statValue = new Double(0.0);
		
		if(jsonTable.containsKey(statId)) {
			statValue = jsonTable.get(statId);
		}
	
		return statValue;		
	}
}
